<?php
namespace app\controller;

use app\BaseController;
use think\facade\Db;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use think\facade\Log;
use think\Request;

class Home extends BaseController
{
    // 获取时间范围
    /**
     * 根据时间类型和自定义时间范围获取统计所需的时间区间
     *
     * @param string $timeType 时间类型，可选值：today, yesterday, last7days, last30days, custom
     * @param string|null $startTime 自定义开始时间，格式：Y-m-d H:i:s
     * @param string|null $endTime 自定义结束时间，格式：Y-m-d H:i:s
     * @return array 包含开始时间和结束时间的数组
     */
    private function getTimeRange($timeType, $startTime, $endTime)
    {
        switch ($timeType) {
            case 'today':
                return [
                    date('Y-m-d 00:00:00'),
                    date('Y-m-d 23:59:59')
                ];
            case 'yesterday':
                return [
                    date('Y-m-d 00:00:00', strtotime('-1 day')),
                    date('Y-m-d 23:59:59', strtotime('-1 day'))
                ];
            case 'last7days':
                return [
                    date('Y-m-d 00:00:00', strtotime('-6 days')),
                    date('Y-m-d 23:59:59')
                ];
            case 'last30days':
                return [
                    date('Y-m-d 00:00:00', strtotime('-29 days')),
                    date('Y-m-d 23:59:59')
                ];
            case 'custom':
                return [$startTime, $endTime];
            default:
                return [$startTime, $endTime];
        }
    }

    // 首页列表统计
    /**
     * 处理首页列表统计请求，返回基础统计信息和时间范围统计信息
     *
     * @param Request $request 请求对象，包含时间类型、自定义时间范围和统计范围类型等参数
     * @return \think\response\Json JSON响应，包含状态码、消息和统计数据
     */
    public function list(Request $request)
    {
        // 获取请求中的时间类型，默认为 today
        $timeType = $request->get('time_type', 'today');
        // 获取请求中的开始时间
        $startTime = $request->get('start_time');
        // 获取请求中的结束时间
        $endTime = $request->get('end_time');
        // 获取请求中的统计范围类型，默认为 day
        $rangeType = $request->get('range_type', 'day');

        // 获取时间范围
        list($start, $end) = $this->getTimeRange($timeType, $startTime, $endTime);

        try {
            // 基础统计
            $data = [
                'home_list' => [
                    // 统计用户总数
                    'user_total' => Db::name('auth_user')->count(),
                    // 统计付费用户总数
                    'paid_user_total' => Db::name('game_order')->where('status', 'paid')->group('user_id')->count(),
                    // 统计产品总数
                    'product_total' => Db::name('game_product')->count()
                ],
                'time_range' => [
                    // 统计开始时间
                    'start' => $start,
                    // 统计结束时间
                    'end' => $end
                ]
            ];

            // 时间范围统计
            $data['statistics'] = $this->getStatisticsData($start, $end, $rangeType);

            return json([
                'code' => 0,
                'msg' => '成功',
                'data' => $data
            ]);
        } catch (\Exception $e) {
            // 记录统计错误日志
            Log::error('统计错误: '.$e->getMessage());
            return json([
                'code' => 1,
                'msg' => '服务器错误',
                'data' => []
            ]);
        }
    }

    // 获取统计数据集
    /**
     * 根据时间范围和统计范围类型获取各项统计数据
     *
     * @param string $start 统计开始时间，格式：Y-m-d H:i:s
     * @param string $end 统计结束时间，格式：Y-m-d H:i:s
     * @param string $rangeType 统计范围类型，可选值：hour, month, day
     * @return array 包含各项统计数据的数组
     */
    private function getStatisticsData($start, $end, $rangeType)
    {
        return [
            // 下载统计
            'download' => $this->getDownloadStats($start, $end),
            // 用户统计
            'user' => $this->getUserStats($start, $end),
            // 账号统计
            'account' => $this->getAccountStats($start, $end),
            // 订单统计
            'order' => $this->getOrderStats($start, $end),
            // 排队统计
            'queue' => $this->getQueueStats(),
            // 支付统计
            'payment' => $this->getPaymentStats($start, $end),
            // 退款统计
            'refund' => $this->getRefundStats($start, $end),
            // 流水详情
            'transaction' => $this->getTransactionDetails($start, $end, $rangeType)
        ];
    }

    // 下载统计
    /**
     * 根据时间范围统计下载相关数据
     *
     * @param string $start 统计开始时间，格式：Y-m-d H:i:s
     * @param string $end 统计结束时间，格式：Y-m-d H:i:s
     * @return array 包含下载成功数量、开始下载数量和成功率的数组
     */
    private function getDownloadStats($start, $end)
    {
        // 统计下载成功的数量
        $success = Db::name('deepseek_download_log')
            ->where('status', 1)
            ->whereBetweenTime('time', $start, $end)
            ->count();

        // 统计开始下载的总数量
        $total = Db::name('deepseek_download_log')
            ->whereBetweenTime('time', $start, $end)
            ->count();

        return [
            // 下载成功数量
            'success_count' => $success,
            // 开始下载数量
            'start_count' => $total,
            // 成功率，保留两位小数
            'success_percent' => $total ? round($success/$total*100, 2) : 0
        ];
    }

    // 用户统计
    /**
     * 根据时间范围统计用户注册和登录相关数据
     *
     * @param string $start 统计开始时间，格式：Y-m-d H:i:s
     * @param string $end 统计结束时间，格式：Y-m-d H:i:s
     * @return array 包含注册用户数量、登录用户数量和注册登录率的数组
     */
    private function getUserStats($start, $end)
    {
        // 统计注册用户数量
        $register = Db::name('auth_user')
            ->whereBetweenTime('created_at', $start, $end)
            ->count();

        // 统计登录用户数量
        $login = Db::name('auth_login_log')
            ->whereBetweenTime('created_at', $start, $end)
            ->group('user_id')
            ->count();

        return [
            // 注册用户数量
            'register_count' => $register,
            // 登录用户数量
            'login_count' => $login,
            // 注册登录率，保留两位小数
            'register_login_percent' => $login ? round($register/$login*100, 2) : 0
        ];
    }

    // 账号统计
    /**
     * 根据时间范围统计账号使用相关数据
     *
     * @param string $start 统计开始时间，格式：Y-m-d H:i:s
     * @param string $end 统计结束时间，格式：Y-m-d H:i:s
     * @return array 包含已使用账号数量、总账号数量和使用率的数组
     */
    private function getAccountStats($start, $end)
    {
        // 统计已使用账号数量
        $used = Db::name('game_account')
            ->where('status', 'used')
            ->whereBetweenTime('created_at', $start, $end)
            ->count();

        // 统计总账号数量
        $total = Db::name('game_account')
            ->whereBetweenTime('created_at', $start, $end)
            ->count();

        return [
            // 已使用账号数量
            'used_count' => $used,
            // 总账号数量
            'total_count' => $total,
            // 使用率，保留两位小数
            'used_percent' => $total ? round($used/$total*100, 2) : 0
        ];
    }

    // 订单统计
    /**
     * 根据时间范围统计订单支付相关数据
     *
     * @param string $start 统计开始时间，格式：Y-m-d H:i:s
     * @param string $end 统计结束时间，格式：Y-m-d H:i:s
     * @return array 包含支付订单数量、创建订单数量和支付率的数组
     */
    private function getOrderStats($start, $end)
    {
        // 统计支付订单数量
        $paid = Db::name('game_order')
            ->where('status', 'paid')
            ->whereBetweenTime('created_at', $start, $end)
            ->count();

        // 统计创建订单数量
        $total = Db::name('game_order')
            ->whereBetweenTime('created_at', $start, $end)
            ->count();

        return [
            // 支付订单数量
            'paid_count' => $paid,
            // 创建订单数量
            'created_count' => $total,
            // 支付率，保留两位小数
            'paid_created_percent' => $total ? round($paid/$total*100, 2) : 0
        ];
    }

    // 排队统计
    /**
     * 统计排队相关数据
     *
     * @return array 包含总排队数量和按游戏分类的排队数量的数组
     */
    private function getQueueStats()
    {
        // 统计总排队数量
        $total = Db::name('game_queue')->count();

        // 按游戏分类统计排队数量
        $byGame = Db::name('game_queue')
            ->alias('q')
            ->join('game_product p', 'q.product_id = p.id')
            ->field('p.name, COUNT(q.id) as queue_count')
            ->group('q.product_id')
            ->select();

        return [
            // 总排队数量
            'total_queue_count' => $total,
            // 按游戏分类的排队数量
            'queue_count_by_game' => $byGame
        ];
    }

    // 支付统计
    /**
     * 根据时间范围统计支付相关数据
     *
     * @param string $start 统计开始时间，格式：Y-m-d H:i:s
     * @param string $end 统计结束时间，格式：Y-m-d H:i:s
     * @return array 包含总支付金额和按游戏分类的支付金额的数组
     */
    private function getPaymentStats($start, $end)
    {
        // 统计总支付金额
        $total = Db::name('game_order_payment')
            ->where('status', 'paid')
            ->whereBetweenTime('paid_at', $start, $end)
            ->sum('amount');

        // 按游戏分类统计支付金额
        $byGame = Db::name('game_order_payment')
            ->alias('op')
            ->join('game_order o', 'op.order_id = o.id')
            ->join('game_order_product opd', 'o.id = opd.order_id')
            ->join('game_product p', 'opd.product_id = p.id')
            ->field('p.name, SUM(op.amount) as payment_amount')
            ->where('op.status', 'paid')
            ->whereBetweenTime('op.paid_at', $start, $end)
            ->group('opd.product_id')
            ->select();

        return [
            // 总支付金额
            'total_payment_amount' => $total,
            // 按游戏分类的支付金额
            'payment_amount_by_game' => $byGame
        ];
    }

    // 退款统计
    /**
     * 根据时间范围统计退款相关数据
     *
     * @param string $start 统计开始时间，格式：Y-m-d H:i:s
     * @param string $end 统计结束时间，格式：Y-m-d H:i:s
     * @return array 包含总退款金额和按游戏分类的退款金额的数组
     */
    private function getRefundStats($start, $end)
    {
        try {
            // 统计总退款金额
            $total = Db::name('game_order')
                ->where('refund_status', 'REFUND_SUCCESS')
                ->whereBetweenTime('created_at', $start, $end)
                ->sum('refund_amount');

            // 按游戏分类统计退款金额
            $byGame = Db::name('game_order')
                ->alias('o')
                ->join('game_order_product opd', 'o.id = opd.order_id')
                ->join('game_product p', 'opd.product_id = p.id')
                ->field('p.name, SUM(o.refund_amount) as refund_amount')
                ->where('o.refund_status', 'REFUND_SUCCESS')
                ->whereBetweenTime('o.created_at', $start, $end)
                ->group('opd.product_id')
                ->select();

            return [
                // 总退款金额
                'total_refund_amount' => $total,
                // 按游戏分类的退款金额
                'refund_amount_by_game' => $byGame
            ];
        } catch (\Exception $e) {
            return [
                // 总退款金额，出错时设为 0
                'total_refund_amount' => 0,
                // 按游戏分类的退款金额，出错时设为空数组
                'refund_amount_by_game' => []
            ];
        }
    }

    // 流水详情
    /**
     * 根据时间范围和统计范围类型获取流水详情数据
     *
     * @param string $start 统计开始时间，格式：Y-m-d H:i:s
     * @param string $end 统计结束时间，格式：Y-m-d H:i:s
     * @param string $rangeType 统计范围类型，可选值：hour, month, day
     * @return array 包含时间区间和交易金额的数组
     */
    private function getTransactionDetails($start, $end, $rangeType)
    {
        switch ($rangeType) {
            case 'hour':
                // 按小时分组
                $group = 'HOUR(paid_at)';
                // 时间格式化
                $format = 'Y-m-d H:00:00';
                break;
            case 'month':
                // 按月份分组
                $group = 'MONTH(paid_at)';
                // 时间格式化
                $format = 'Y-m';
                break;
            default:
                // 按日期分组
                $group = 'DATE(paid_at)';
                // 时间格式化
                $format = 'Y-m-d';
        }

        // 获取流水详情数据
        $data = Db::name('game_order_payment')
            ->whereBetweenTime('paid_at', $start, $end)
            ->field("{$group} as time_group, SUM(amount) as amount")
            ->group($group)
            ->select();

        // 格式化时间
        foreach ($data as &$item) {
            $item['time_period'] = date($format, strtotime($start . " +{$item['time_group']} " . $rangeType));
        }

        return $data;
    }

    // 导出功能
    /**
     * 处理导出统计数据到 Excel 文件的请求
     *
     * @param Request $request 请求对象，包含时间类型、自定义时间范围和统计范围类型等参数
     * @return \think\response\Json JSON响应，包含状态码、消息和数据
     */
    public function export(Request $request)
    {
        // 获取请求中的时间类型，默认为 today
        $timeType = $request->get('time_type', 'today');
        // 获取请求中的开始时间
        $startTime = $request->get('start_time');
        // 获取请求中的结束时间
        $endTime = $request->get('end_time');
        // 获取请求中的统计范围类型，默认为 day
        $rangeType = $request->get('range_type', 'day');

        list($start, $end) = $this->getTimeRange($timeType, $startTime, $endTime);

        try {
            // 获取统计数据
            $data = $this->getStatisticsData($start, $end, $rangeType);

            // 创建Spreadsheet对象
            $spreadsheet = new Spreadsheet();
            $sheet = $spreadsheet->getActiveSheet();

            // 填充数据
            $this->fillExportSheet($sheet, $data);

            // 输出文件
            $filename = 'stats_export_'.date('YmdHis').'.xlsx';
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            header('Content-Disposition: attachment;filename="'.$filename.'"');
            
            $writer = new Xlsx($spreadsheet);
            $writer->save('php://output');
            exit;

        } catch (\Exception $e) {
            // 记录导出错误日志
            Log::error('导出错误: '.$e->getMessage());
            return json([
                'code' => 1,
                'msg' => '导出失败',
                'data' => []
            ]);
        }
    }

    // 填充导出表格
    /**
     * 将统计数据填充到 Excel 表格中
     *
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet Excel 工作表对象
     * @param array $data 统计数据数组
     */
    private function fillExportSheet($sheet, $data)
    {
        $row = 1;
        
        // 基础统计
        $sheet->setCellValue('A'.$row, '用户总数')
              ->setCellValue('B'.$row, $data['home_list']['user_total']);
        $row++;
        $sheet->setCellValue('A'.$row, '付费用户总数')
              ->setCellValue('B'.$row, $data['home_list']['paid_user_total']);
        $row++;
        $sheet->setCellValue('A'.$row, '产品总数')
              ->setCellValue('B'.$row, $data['home_list']['product_total']);
        $row++;

        // 时间范围统计
        $row += 2;
        $sheet->setCellValue('A'.$row, '下载统计')
              ->setCellValue('B'.$row, '成功下载')
              ->setCellValue('C'.$row, $data['download']['success_count']);
        $row++;
        $sheet->setCellValue('B'.$row, '开始下载')
              ->setCellValue('C'.$row, $data['download']['start_count']);
        $row++;
        $sheet->setCellValue('B'.$row, '成功率')
              ->setCellValue('C'.$row, $data['download']['success_percent'].'%');
        $row++;

        $sheet->setCellValue('A'.$row, '用户统计')
              ->setCellValue('B'.$row, '注册用户')
              ->setCellValue('C'.$row, $data['user']['register_count']);
        $row++;
        $sheet->setCellValue('B'.$row, '登录用户')
              ->setCellValue('C'.$row, $data['user']['login_count']);
        $row++;
        $sheet->setCellValue('B'.$row, '注册登录率')
              ->setCellValue('C'.$row, $data['user']['register_login_percent'].'%');
        $row++;

        $sheet->setCellValue('A'.$row, '账号统计')
              ->setCellValue('B'.$row, '已使用账号')
              ->setCellValue('C'.$row, $data['account']['used_count']);
        $row++;
        $sheet->setCellValue('B'.$row, '总账号数')
              ->setCellValue('C'.$row, $data['account']['total_count']);
        $row++;
        $sheet->setCellValue('B'.$row, '使用率')
              ->setCellValue('C'.$row, $data['account']['used_percent'].'%');
        $row++;

        $sheet->setCellValue('A'.$row, '订单统计')
              ->setCellValue('B'.$row, '支付订单')
              ->setCellValue('C'.$row, $data['order']['paid_count']);
        $row++;
        $sheet->setCellValue('B'.$row, '创建订单')
              ->setCellValue('C'.$row, $data['order']['created_count']);
        $row++;
        $sheet->setCellValue('B'.$row, '支付率')
              ->setCellValue('C'.$row, $data['order']['paid_created_percent'].'%');
        $row++;

        $sheet->setCellValue('A'.$row, '排队统计')
              ->setCellValue('B'.$row, '总排队数')
              ->setCellValue('C'.$row, $data['queue']['total_queue_count']);
        $row++;
        foreach ($data['queue']['queue_count_by_game'] as $queue) {
            $sheet->setCellValue('B'.$row, $queue['name'])
                  ->setCellValue('C'.$row, $queue['queue_count']);
            $row++;
        }

        $sheet->setCellValue('A'.$row, '支付统计')
              ->setCellValue('B'.$row, '总支付金额')
              ->setCellValue('C'.$row, $data['payment']['total_payment_amount']);
        $row++;
        foreach ($data['payment']['payment_amount_by_game'] as $payment) {
            $sheet->setCellValue('B'.$row, $payment['name'])
                  ->setCellValue('C'.$row, $payment['payment_amount']);
            $row++;
        }

        $sheet->setCellValue('A'.$row, '退款统计')
              ->setCellValue('B'.$row, '总退款金额')
              ->setCellValue('C'.$row, $data['refund']['total_refund_amount']);
        $row++;
        foreach ($data['refund']['refund_amount_by_game'] as $refund) {
            $sheet->setCellValue('B'.$row, $refund['name'])
                  ->setCellValue('C'.$row, $refund['refund_amount']);
            $row++;
        }

        // 流水详情
        $row += 2;
        $sheet->setCellValue('A'.$row, '时间区间')
              ->setCellValue('B'.$row, '交易金额');
        foreach ($data['transaction'] as $item) {
            $row++;
            $sheet->setCellValue('A'.$row, $item['time_period'])
                  ->setCellValue('B'.$row, $item['amount']);
        }
    }
}    